
#ifndef __LIBERTY_ENGINE_CONTEXT_H__
#define __LIBERTY_ENGINE_CONTEXT_H__

#include <list>
#include <vector>

#include <Liberty3D/Liberty3D.h>
#include <Liberty3D/Engine/Coroutine.h>
#include <Liberty3D/Engine/Performance.h>

namespace Liberty { namespace Engine {
    class Context : public std::enable_shared_from_this<Context> {
    public:
        typedef std::vector<std::shared_ptr<GameObject>> GameObjectVector;
        typedef std::vector<std::shared_ptr<Component>>  ComponentVector;
        typedef std::list<CoroutineEntry>                CoroutineVector;

        typedef std::list<std::shared_ptr<GameObject>> GameObjectList;
        typedef std::list<std::shared_ptr<Component>>  ComponentList;

    protected:
        GameObjectVector _gameObjects;
        ComponentVector  _components;
        CoroutineVector  _coroutines;

        GameObjectList _removedGameObjects;
        ComponentList  _removedComponents;

        GameObjectList _addedGameObjects;
        ComponentList  _addedComponents;

    public:
        Context();
        ~Context();

    protected:
        bool _running;

        Performance::Counter _stopTime;

        Performance::Counter _fixedDelta;
        Performance::Counter _maxDelta;
        Performance::Counter _maxFrameRate;

        Performance::Counter _passStartTime;
        Performance::Counter _lastPassStartTime;
        Performance::Counter _lastFixedUpdateTime;
        Performance::Counter _gameLoadTime;
        Performance::Counter _levelLoadTime;
        unsigned int         _frameCount;
        unsigned int         _renderedFrameCount;

    protected:
        Performance::Counter _lastFixedUpdate;
        Performance::Counter _nextFixedUpdate;
        Performance::Counter _nextUpdate;

    public:
        inline Performance::Counter fixedDelta() const { return _fixedDelta; }
        
    public:
        void start();
        void stop();
        bool tick(Performance::Counter& nextTick);

        void handleException(const std::exception& ex);

    public:
        std::shared_ptr<GameObject> createGameObject(const std::shared_ptr<GameObject> parent, const std::string& name);
        std::shared_ptr<Component>  addComponent    (const std::shared_ptr<GameObject> parent, const std::shared_ptr<Component>& component);

    protected:
        void addGameObject(const std::shared_ptr<GameObject>&);
        void addComponent (const std::shared_ptr<Component>&);

        void removeGameObject(const std::shared_ptr<GameObject>&);
        void removeComponent (const std::shared_ptr<Component>&);

        void cleanup();

    protected:
        void fixedUpdate();
        void update();
        void lateUpdate();

        void animate();
        void frameRender();

        void coroutine(Performance::Counter currentTime, bool doFixedFrame);
    };
}}

#endif
